#!/bin/bash
# USAGE:
#	settings option [argument]
#	settings apply variableName
#	settings apply [-rq] variableName1=variableValue1 [variableName2 variableName3=...]
#	settings check
#	settings fix [-q]
#	settings init [-q]
#	settings list
#	settings raw
#	settings save [fileName]
#	settings load [fileName]
#	settings reset
#	settings clear
#
# DESCRIPTION:
#  SETTINGS is an internal ADORE command. 
#  It aims at providing a smooth interface for modifying ADORE 
#  settings.
#
# INPUT:
#  settings apply [-rq] variableName: updates settings that depend on
#	variableName. By default this is not done in a recursive way. Use 
#       'settings check' for possible mismatches. Settings apply can also assign values 
#       using the variableName=value syntax.  
#       -r: Recursive checks can be specified using -r option. 
#	-q: Quiet. Suppresses the printing of the changed settings.
#
#  settings check: looks for differences between ADORE's 
#	expectations and current values. Handy for finding 
#	errors due to recursive dependancies.
#
#  settings fix: after "check"ing you can accept suggested changes 
#	using the variables. Check will display a reference line.
#	-q: Quiet. Suppresses the printing of the changed settings.
#
#  settings init: will ask the user some questions to create an initial 
#	settings file. Useful when starting a new project. 
#
#  settings list: will list the current settings as seen by ADORE.
#
#  settings raw: displays the unprocessed settings with USERS
#	changes. This can be saved with the save function.
#
#  settings save [fileName]: saves the settings (raw) to the file.
#	if fileName is not specified './settings.set' is used.
#
#  settings load [fileName]: loads the settings to the environment.
#	if filenName is not specified './settings.set' is used.
#
#  settings reset: initializes the environment. User settings file is loaded.
#
#  settings clear: clears all ADORE settings and resets ${ADORESCR} and ${ADOREFOLDER}
#

clearSettings(){
    #unset all variables##
    _ADORESCR=${ADORESCR}
    while read -r line; do
      #get right side of the line
        #if no && in the line move on...
      [ "${line}" == "${line##*&&}" ] && continue
        #else ..
      line=${line##*&&};
      #get the variable name
      varName=${line%%=*}
      #clear the variable
      eval "unset ${varName}" 
    done < "${ADOREFOLDER}/set/default.set"
    ADORESCR=${_ADORESCR}
    ADOREFOLDER=${ADORESCR//\/scr/}
    unset _ADORESCR
}



reset2DefaultSettings(){
    #reset to defaults... 
    while read -r line; do
      #get right side of the line
      [ "${line}" == "${line##*&&}" ] && continue
      line=${line##*&&};
      #get the variable name
      varName=${line%%=*}
      varValue=${line#*=}
      #echo ${varName}="${varValue}"
      eval ${varName}="${varValue}"
    done < "${ADOREFOLDER}/set/default.set"     
}

dumpDefaultSettings(){
    tempFile=${1}
    #dump the default to a temp file. 
    rm -rf ${tempFile}
    #cat "${ADOREFOLDER}/set/default.set" | while read -r line; do
    grep -v "^$" "${ADOREFOLDER}/set/default.set" |grep -v "^#" | while read -r line; do
      #get right side of the line
      echo ${line##*&&} >> ${tempFile}
    done
}

dumpRawSettings(){
    tempFile=${1}
    generateRandomString;
    tempFile2=${randomString};
    #######################################
    #show settings without shell expansions
    #######################################
    dumpDefaultSettings ${tempFile}
    ####read user.set and make required changes##
    #############################################
    cat "${u}" | while read -r line; do
      #if it has relative values replace default.      
      rightSide=${line##*=} 
      evalRightSide=`eval echo ${rightSide} 2> /dev/null`

      [ -z "${evalRightSide}" ] && continue; #if no value continue
      [ -z "${line%%=*}" ] && continue; #if no value continue

      #check if rightside is relative
      #if [ "${rightSide}" != "${evalRightSide}" ]; then
        #echo rightSide: ${rightSide}
        #echo evalRightSide: ${evalRightSide}
        #search .tempfile and replace line
        #lineNumber=`grep -n ${line%%=*}| cut -f1 -d:`        
 #       echo A: ${line%%=*} ${rightSide}
 #       sed "s/\(^${line%%=*}=\)\(..*$\)/\1${rightSide}/" ${tempFile} > ${tempFile}2
        sed "s@\(^${line%%=*}=\)\(..*$\)@\1${rightSide}@" ${tempFile} > ${tempFile2}
        mv ${tempFile2} ${tempFile}
      #fi
    done
##    echo not implemented yet.
    
}

function settingsOK(){
    #check for inconsistent changes. like ${master} is changed but ${m_resfiles} is still old.
      #loop over _ref_variables. and check for mismatches
      for var in ${!_rel_*}
      do
        #echo ${var}=${!var} #display contents
        #echo ${var}=${var##*_rel_} # display setting to be modified
        setting=${var##*_rel_} # get setting name
        relativeValue=`eval ${!var}`
        #echo ${setting}=${!setting} #display current settings
        #echo ${setting}=${relativeValue}
        [ -z "${relativeValue}" ] && continue; #if relative value is "" do not change values.
        if [ "${!setting}" != "${relativeValue}" ]; then
          return 1;
        fi
      done
      return 0;
}

function settings_save(){
    #save settings to a file
    #rm -rf ${2:-settings.set} #clear if file exists
    saveFileName=${2:-settings.set}
    generateRandomString; 
    tempFile=${randomString}

    echo "Please wait while I check the current environment..."

    dumpDefaultSettings ${tempFile}
    
    if [ -e "${saveFileName}" ]; then
      if strcmpi "${overwrite}" "on"
        then
        rm  ${saveFileName}
      else
        if ask "Shall I delete the old ${saveFileName}?"
          then 
            rm  ${saveFileName}
        else
          return
        fi
      fi
    fi
    
    #check to see if current environment is set differently 
    #######################################################
    cat ${tempFile} | while read -r line; do          
      leftSide=${line%%=*}; #get the left side of name=value pair.
      leftSide="${leftSide}[@]"; #try to get the complete array if available.
      				 #if variable is not an array this should default to 
      				 #the variable value. 
      leftSideEval=${!leftSide}; #indirect reference of the name. See active value.
      [ -z "${leftSide}" ] && continue; #if no value continue
      #[ -z "${leftSideEval}" ] && continue; #if no value continue
      
      rightSide=${line##*=}; # get the right side (value) (default)
      #if [[ "${leftSide}" == *_rel* ]]; then
      #  rightSideEval=`eval echo ${rightSide}` #(evaluate default)
      #  echo ..${leftSideEval}..=..${rightSideEval}../..${rightSide}
      #else
        rightSideEval=`eval echo "${rightSide}" 2> /dev/null` #(evaluate default)
      #fi
      #[ -z "${rightSideEval}" ] && continue; #if no value continue      

      if [ "${leftSideEval}" != "${rightSideEval}" ]; then
#        echo ..${line%%=*}..=..${!leftSide}..

#        echo ${line%%=*}=\"${!leftSide}\" >> ${saveFileName}
        #Since rev.52 we need to be able to save arrays as settings
        #check if first character is a bracket
        local testStr=( "${!leftSide}" );
        #There apparently is a difference between @ and *, see http://www.linuxjournal.com/content/bash-arrays
        if [ "${#testStr[*]}" -gt "1" ]; then
          #we are saving an array no quotes. use brackets.
          echo "${line%%=*}=( ${leftSideEval} )" >> ${saveFileName}
	else
          echo ${line%%=*}=\"${!leftSide}\" >> ${saveFileName}
	fi           
      fi    
    done
    #mv ${tempFile} ${saveFileName}	
    rm ${tempFile}
    echo "Settings saved to ${saveFileName}"
}

function settings_load(){
    #load settings from file
    if [ "${2-undefined}" == "undefined" ];then
      loadFile="./settings.set";
    else
      loadFile=${2};
    fi
    clearSettings;
    u=`canonicalPath ${loadFile}`
    unset loadFile
    initialize
}

function settings_raw(){
    #show settings without shell expansions
    tempFile=".tempfile"
    dumpRawSettings ${tempFile}
    #check to see if current environment is set differently 
    #######################################################
    cat ${tempFile} | while read -r line; do          
      leftSide=${line%%=*}; #get the left side of name=value pair.
      leftSideEval=${!leftSide}; #indirect reference of the name. See active value.
      [ -z "${leftSide}" ] && continue; #if no value continue
      [ -z "${leftSideEval}" ] && continue; #if no value continue
      
      rightSide=${line##*=}; # get the right side (value)
      rightSideEval=`eval echo "${rightSide}" 2> /dev/null` 
      [ -z "${rightSideEval}" ] && continue; #if no value continue      

      if [ "${leftSideEval}" != "${rightSideEval}" ]; then
	sed "s@\(^${line%%=*}=\)\(..*$\)@\1${leftSideEval}@" ${tempFile} > ${tempFile}2
        mv ${tempFile}2 ${tempFile}        
      fi    
    done
    cat ${tempFile}
    rm -rf ${tempFile}  

    #check if right side exists
    #if [[ "${line}" == *\&\&* ]]; then           
    #  #get right side of the line      
    #  line=`eval echo "${line##*&&}"`
    #  if [ -n "${line%%=*}" ]; then 
    #    #echo ${line%%=*}=${line##*=}
    #    line=${line%%=*};
    #    echo ${line}=${!line}
    #  fi
    #fi
}

function settings_check(){
    #check for inconsistent changes. like ${master} is changed but ${m_resfiles} is still old.
      #loop over _ref_variables. and check for mismatches
      suggestionLine="settings fix"
      for var in ${!_rel_*}
      do
        #echo ${var}=${!var} #display contents
        #echo ${var}=${var##*_rel_} # display setting to be modified
        setting=${var##*_rel_} # get setting name
        relativeValue=`eval ${!var}`
        #echo ${setting}=${!setting} #display current settings
        #echo ${setting}=${relativeValue}
        [ -z "${relativeValue}" ] && continue; #if relative value is "" do not change values.
        if [ "${!setting}" != "${relativeValue}" ]; then
          echo " active    ${setting}=${!setting}"        
          echo " suggested ${setting}=${relativeValue}"
          echo " reason    _rel_${setting}=\"${!var}\""          
          echo " "
          suggestionLine="${suggestionLine} ${setting}"
        fi
      done
      if [ "${suggestionLine}" != "settings fix" ]; then
	echo "May I suggest we run the command below? I might be wrong for some settings though..."
        echo ${suggestionLine}
        echo " "
      else
        echo "Everything seems fine."
      fi

#    tempFile=".tempfile"
#    dumpRawSettings ${tempFile}
#    #check to see if current environment is set differently 
#    #######################################################
#    cat ${tempFile} | while read -r line; do          
#      leftSide=${line%%=*}; #get the left side of name=value pair.
#      leftSideEval=${!leftSide}; #indirect reference of the name. See active value.
#      [ -z "${leftSide}" ] && continue; #if no value continue
#      [ -z "${leftSideEval}" ] && continue; #if no value continue
#      
#      rightSide=${line##*=}; # get the right side (value)
#      rightSideEval=`eval echo "${rightSide}" 2> /dev/null` 
#      [ -z "${rightSideEval}" ] && continue; #if no value continue      
#
#      if [ "${leftSideEval}" != "${rightSideEval}" ]; then
#        echo " active  ${leftSide}=${leftSideEval}"        
#        echo " default ${leftSide}=${rightSide}"
#        echo " "
#        #echo B: ${line%%=*} ${leftSideEval}
#	#echo sed "s/\(^${line%%=*}=\)\(..*$\)/\1${leftSideEval}/" ${tempFile}
#	#sed "s/\(^${line%%=*}=\)\(..*$\)/\1${leftSideEval}/" ${tempFile} > ${tempFile}2
#	#sed "s@\(^${line%%=*}=\)\(..*$\)@\1${leftSideEval}@" ${tempFile} > ${tempFile}2
#        #mv ${tempFile}2 ${tempFile}        
#      fi    
#    done
#    #cat ${tempFile}
#    rm -rf ${tempFile}  
}

function settings_apply(){
  local r=1; #off=1, on=0
  local q=1; #off=1, on=0
  #echo "${@}"
  unset OPTIND OPTARG
  while getopts "rq" flag "${@}"
  do
    #echo "$flag" $OPTIND $OPTARG
    if [ "${flag}" == "?" ]; then
      continue;
    else
      [ "${flag}" == "r" ] && r=0
      [ "${flag}" == "q" ] && q=0
    fi
  done
  
  #Remove already parsed options
  local k
  for ((k=1; k<$OPTIND; k++ ))
  do
    shift
  done
#  if [ "${2}" == "-r" ]; then
#    recursive=0;
#    shift;
#  fi
  #Get the remaining 
  if [ "${1-undefined}" != "undefined" ]; then
    #loop over input. 
    for (( k=1 ; k<=$# ; k++ )); do
      #check if this parameter is an assignment statement
      inputPar="${!k}";
      if [[ "${inputPar}" == *=* ]]; then
        inputVar=${inputPar%%=*};
        #make the assignment
        eval ${inputVar}=\"${inputPar#*=}\"
      else
        inputVar=${inputPar};  
      fi
      [ "${q}" -eq "1" ] && echo ${inputVar}=\"${!inputVar}\"
      #apply setting with all dependents. like ${master} is changed so should ${m_resfiles}.
      #loop over _ref_variables. and check for changes.
      for var in ${!_rel_*}; do
        #echo ${var}=${!var} #display contents
        #echo ${var}=${var##*_rel_} # display setting to be modified
        setting=${var##*_rel_} # get setting name
        relativeValue=`eval ${!var}`
        if [[ ${!var} == *${inputVar}* ]]; then
          #echo ${setting}=${!setting} #display current settings
          #echo ${setting}=${relativeValue}
          [ -z "${relativeValue}" ] && continue; #if relative value is "" do not change values.
          [ "${setting}" == "${inputVar}" ] && continue; #Do not overwrite users choice. 
          if [ "${!setting}" != "${relativeValue}" ]; then
            [ "${q}" -eq "1" ] && echo ${setting}=${relativeValue}
            #eval ${setting}=\"${relativeValue}\"
            eval "${setting}=\"${relativeValue}\""
          fi
        fi
      done #for relative definitions
    done #for input
    #echo "r=${r}"
    [ "${r}" -eq "1" ] && return; #if recursive is not requested return. 
    local loopCounter=0
    local qFlag=""
    [ "${q}" -eq "0" ] && qFlag="-q" #if quiet set flag for fix.
    while [ ${loopCounter} -lt 10 ]; do
      settings fix ${qFlag} 
      [ settingsOK ] && break; #if no change is detected no need to continue.
      let loopCounter=loopCounter+1;
    done #while recursive 
    if [ ${loopCounter} -eq 10 ]; then
      echo "Maximum loopcount (10) reached, there might be a problem with the settings."
      echo "This might happen when the value of a variable changes at each loop."
    fi
  else
    echo " USAGE:"
    echo "     . settings apply variableName"
    echo " ex: . settings apply master"
  fi
}

function settings_fix(){
    local q=1;
    if [[ "${2}" == "-q" ]]; then
      q=0; #quiet on=0, off=1
      shift
    fi
    if [ "${2:-undefined}" == "undefined" ]; then
      [ "${q}" -eq "1" ] && echo ""
      [ "${q}" -eq "1" ] && echo "Applying all suggested changes."
      for var in ${!_rel_*}
      do
        #echo ${var}=${!var} #display contents
        #echo ${var}=${var##*_rel_} # display setting to be modified
        setting=${var##*_rel_} # get setting name
        relativeValue=`eval ${!var}`
        #echo ${setting}=${!setting} #display current settings
        #echo ${setting}=${relativeValue}
        [ -z "${relativeValue}" ] && continue; #if relative value is "" do not change values.
        if [ "${!setting}" != "${relativeValue}" ]; then
          [ ! ${q} ] && echo "${setting}=\"${relativeValue}\""        
          eval "${setting}=\"${relativeValue}\""
        fi
      done
    else
      for (( k=2 ; k<=$# ; k++ ))
      do
        #echo ${!k}
        setting=${!k}
        relativeName="_rel_${!k}"
        #echo ${relativeName}
        relativeValue=`eval ${!relativeName}`
        [ "${q}" -eq "1" ] && echo "${setting}=\"${relativeValue}\""
        eval "${setting}=\"${relativeValue}\"" 
      done
    fi
}

function settings_list(){
    #generateRandomString; 
    #tempFile=${randomString}

    #dumpDefaultSettings ${tempFile}

    #cat ${tempFile} | while read -r line; do          
    #cat "${ADOREFOLDER}/set/default.set" | while read -r line; do          
    #  leftSide=${line%%=*}; #get the left side of name=value pair.
    #  leftSideEval=${!leftSide}; #indirect reference of the name. See active value.
    #  #[ -z "${leftSide}" ] && continue; #if no value continue
    #  #[ -z "${leftSideEval}" ] && continue; #if no value continue
    #  echo ..${leftSide}..=..${leftSideEval}..
    #done

    local line varName varValue varNameArray
    #default: show settings
    cat "${ADOREFOLDER}/set/default.set" |while read -r line; do
      if [[ "${line}" == *SECTION* ]];then #check if section line 
        echo "[${line##*=}]"
      elif [[ "${line}" == *\&\&* ]]; then  #check if right side exists
        #get right side of the line after &&     
        #line=`eval echo "${line##*&&}"` 
        line=${line##*&&}
        #echo ..${line}..
        if [ -n "${line%%=*}" ]; then 
          #echo ${line%%=*}=${line##*=}
          varName=${line%%=*};
          varName=${varName// /};#remove spaces
          varNameArray="${varName}[*]" #Works for normal variables and ARRAYS.
          varValue=${!varNameArray};
          #indirect referencing in the line below {!
          if [[ ${varName} == *_rel_* ]]; then
            echo "${varName}='${varValue}'"
          else
            echo "${varName}=\"${varValue}\""
          fi
        fi
      fi
    done 
}

function settings_init(){
 #first apply settings passed in the command line
 shift
 [ "${1}"=="-q" ] && q='-q' && shift || q=''
 [ $# -gt 0 ] && settings apply -r ${q} "$@"
 
 bold "I am going to ask you a few questions to initialize your settings."
 echo "The values shown in square brackets [] are existing settings."
 echo "If the default settings is correct you can enter blank to continue with it."
 if ask "Shall we start?"
 then  
   #now ask some questions
   local variables
   bold "What is the projectFolder? [${projectFolder}]"
   echo "Your current path is: ${PWD}"
   read -e userInput
   [ -n "${userInput}" ] && settings apply -r ${q} projectFolder="${userInput}"

   bold "What is the runName? [${runName}]"
   read userInput
   [ -n "${userInput}" ] && settings apply -r ${q} runName="${userInput}"
   
   if [ ! -d "${dataFolder}" ]; then 
     if ask "$dataFolder does not exist. Would you like me to run create it?"
     then
       echo "Please specify where your data is currently located:"
       read -e userInput
       scenes init "${userInput}"
     fi
   elif [ "$(ls -A ${dataFolder})" ]; then 
     echo "Data folder exists but is empty."
     echo "Please specify where your data is currently located:"
     read -e userInput
     scenes init "${userInput}"
   else
     bold "dataFolder is currently set as: $dataFolder" 
     if ask "Do you want to create a new dataFolder?"
     then 
       echo "Please enter the name of new data folder:"
       read -e userInput
       [ -n "${userInput}" ] && settings apply -r ${q} dataFolder="${userInput}"
       echo "Please specify where your data is currently located:"
       read -e userInput
       scenes init "${userInput}"
     fi
   fi
   
   bold "In the dataFolder I found the following scenes:"
   scenes include
   if ask "Do you want to exclude any scenes?"
   then 
     echo "Please specify the scenes separated by space"
     read userInput
     scenes exclude ${userInput}
   fi

   if [ ! -f "${m_in_dat}" ]; then
     if [ -z "${master}" ]; then
       bold "Master folder is not set."
       echo "Please enter the master from the following options:"
       scenes include
       read userInput
       [ -n "${userInput}" ] && settings apply -r ${q} master="${userInput}"
     fi       
     if [ -z "${slave}" ]; then
       bold "Slave folder is not set."
       echo "Please enter the slave from the following options:"
       scenes include
       read userInput
       [ -n "${userInput}" ] && settings apply -r ${q} slave="${userInput}"
     fi       
        
     #Seems like scenes init was not run. 
     bold "What is the dataFile pattern? [${dataFile}]"
     echo "Here is the listing of the files in the current master folder."
     ls ${dataFolder}/${master}
     read userInput
     [ -n "${userInput}" ] && settings apply -r ${q} dataFile="${userInput}"

     if ask "Do you also want to enter the patterns for leader, volume and null files?"
     then
       bold "What is the leaderFile pattern? [${leaderFile}]"
       read userInput
       [ -n "${userInput}" ] && settings apply -r ${q} leaderFile="${userInput}"
       bold "What is the volumeFile pattern? [${volumeFile}]"
       read userInput
       [ -n "${userInput}" ] && settings apply -r ${q} volumeFile="${userInput}"
       bold "What is the nullFile pattern? [${nullFile}]"
       read userInput
       [ -n "${userInput}" ] && settings apply -r ${q} nullFile="${userInput}"
     fi  

     bold "What is the m_in_method? Available options are: ERS, ASAR, RSAT, ATLANTIS, JERS, ALOS, TSX, CSK, GAMMA"
     echo "Current setting: [${m_in_method}]"
     read userInput
     [ -n "${userInput}" ] && settings apply -r ${q} m_in_method="${userInput}"
   fi
  
   bold "What is the m_orbdir? This is the folder that has the arclist file for getorb."
   echo "Current setting: [${m_orbdir}]"
   read userInput
   [ -n "${userInput}" ] && settings apply -r ${q} m_orbdir="${userInput}"
   
   bold "What would you like to name this settings file?"
   echo "Current setting: [settings.set]"
   read userInput
   settings save ${userInput}
 fi
}

case ${1} in
  save)
    settings_save "$@"
  ;;
  load)
    settings_load "$@"
  ;;
  reset)
    echo "Loading default settings..."
    reset2DefaultSettings
  ;;
  clear)
    echo "Removing all settings..."
    clearSettings
  ;;
  raw)
    settings_raw
  ;;
  check)
    settings_check
  ;;  
  apply)
    shift
    settings_apply "$@"
  ;;  
  fix)
    settings_fix "$@"
  ;;
  init)
    settings_init "$@"
  ;;
  list)
    settings_list
  ;;
  *)
    echo "Unknown option. You can get help with: ? settings"
  ;;
esac
   
